/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.policy;

import java.util.List;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.editpolicies.ConnectionEndpointEditPolicy;
import org.eclipse.gef.editpolicies.FeedbackHelper;
import org.eclipse.gef.requests.ReconnectRequest;

import com.cea.papyrus.diagram.sequence.sedi.edit.SeDiSubpartEditPart;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetAnchorHintsCommand;


/**
 * 
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class LinkEndpointEditPolicy extends ConnectionEndpointEditPolicy{

	protected void addSelectionHandles() {
		super.addSelectionHandles();
		getConnectionFigure().setLineWidth(2);
	}
	
	protected PolylineConnection getConnectionFigure(){
		return (PolylineConnection)((GraphicalEditPart)getHost()).getFigure();
	}
	
	protected void removeSelectionHandles(){
		super.removeSelectionHandles();
		getConnectionFigure().setLineWidth(0);
	}
	
	// Enhanced feedback for move message ------------------------------------
	
	private ConnectionAnchor originalSourceAnchor;
	private ConnectionAnchor originalTargetAnchor;
	private SeDiFeedbackHelper sourceFeedbackHelper;
	
	/**
	 * Lazily creates and returns the feedback helper for the given request. The helper will
	 * be configured as either moving the source or target end of the connection.
	 * @param request the reconnect request
	 * @return the feedback helper
	 */
	protected FeedbackHelper getFeedbackHelper(ReconnectRequest request) {
		if (request.isMovingStartAnchor()) {
			if (sourceFeedbackHelper == null) {
				sourceFeedbackHelper = new SeDiFeedbackHelper();
				sourceFeedbackHelper.setConnection(getConnection());
			}
			return sourceFeedbackHelper;			
		}
		else
			return super.getFeedbackHelper(request);
	}

	/**
	 * Shows or updates connection move feedback.  Called whenever a show feedback request is
	 * received for reconnection.
	 * @param request the reconnect request
	 */
	@SuppressWarnings("unchecked")
	protected void showConnectionMoveFeedback(ReconnectRequest request) {
		if (request.isMovingStartAnchor()) {
			SeDiSubpartEditPart source = null;
			if (request.getTarget() instanceof SeDiSubpartEditPart)
				source = (SeDiSubpartEditPart)request.getTarget();
			if (originalSourceAnchor == null) {
				originalSourceAnchor = getConnection().getSourceAnchor();
				originalTargetAnchor = getConnection().getTargetAnchor();
			}
			
			ConnectionAnchor sourceAnchor = null; 
			ConnectionAnchor targetAnchor = null;
			if (source != null) {
				final CompoundCommand ccmd = (CompoundCommand) source.getCommand(request);
				if (ccmd != null) {
					for (final Command cmd : (List<Command>) ccmd.getCommands()) {
						if (cmd.getClass() == SetAnchorHintsCommand.class) {
							final SetAnchorHintsCommand hintsCmd = (SetAnchorHintsCommand) cmd;
							if (hintsCmd.getSourceHint() != null)
								sourceAnchor = source.getConnectionAnchor(hintsCmd.getSourceHint());
							if (hintsCmd.getTargetHint() != null) {
								final SeDiSubpartEditPart target = (SeDiSubpartEditPart)
									request.getConnectionEditPart().getTarget();
								targetAnchor = target.getConnectionAnchor(hintsCmd.getTargetHint());
							}
						}
					}
				}
				
				if (sourceAnchor == null)
					sourceAnchor = source.getSourceConnectionAnchor(request);;				
				if (targetAnchor == null)
					targetAnchor = originalTargetAnchor;				
			}
			else {
				sourceAnchor = originalSourceAnchor;
				targetAnchor = originalTargetAnchor;
			}
			final SeDiFeedbackHelper helper = (SeDiFeedbackHelper) getFeedbackHelper(request);
			helper.update(sourceAnchor, targetAnchor);
		}
		else
			super.showConnectionMoveFeedback(request);
	}
	
	/**
	 * Erases connection move feedback. This method is called when a ReconnectRequest is
	 * received.
	 * @param request the reconnect request.
	 */
	protected void eraseConnectionMoveFeedback(ReconnectRequest request) {
		super.eraseConnectionMoveFeedback(request);
		if (originalSourceAnchor == null)
			return;
		getConnection().setSourceAnchor(originalSourceAnchor);
		originalSourceAnchor = null;
		getConnection().setTargetAnchor(originalTargetAnchor);
		originalTargetAnchor = null;
	}
	
	private static class SeDiFeedbackHelper extends FeedbackHelper {
		public void update(ConnectionAnchor sourceAnchor, ConnectionAnchor targetAnchor) {
			if (sourceAnchor == null)
				throw new IllegalArgumentException("source anchor");
			//if (targetAnchor == null)
			//	throw new IllegalArgumentException("target anchor");
			getConnection().setSourceAnchor(sourceAnchor);
			getConnection().setTargetAnchor(targetAnchor);				
		}	
	}
}
